{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 对话\n",
    "如何使用针对对话优化的代理。其他代理通常针对使用工具进行优化，以找出最佳响应，这在对话环境中并不理想，因为您可能希望代理也能够与用户聊天。\n",
    "\n",
    "我们将它与标准的 ReAct 代理进行比较，主要区别在于提示。我们希望它更具对话性。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "#设置代理\n",
    "import os\n",
    "\n",
    "os.environ['http_proxy'] = 'http://127.0.0.1:10809'\n",
    "os.environ['https_proxy'] = 'http://127.0.0.1:10809'\n",
    "# 这里我们需要用到google的搜索api\n",
    "# 在这个网址https://serpapi.com/search-api，但是需要你用邮箱验证和手机号验证\n",
    "os.environ[\"SERPAPI_API_KEY\"] = \"5266dxxxxxxx266xxxxxxxxx95b7a6891\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Collecting google-search-results\n",
      "  Using cached google_search_results-2.4.2-py3-none-any.whl\n",
      "Requirement already satisfied: requests in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from google-search-results) (2.31.0)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from requests->google-search-results) (3.3.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from requests->google-search-results) (3.6)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from requests->google-search-results) (2.1.0)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from requests->google-search-results) (2023.11.17)\n",
      "Installing collected packages: google-search-results\n",
      "Successfully installed google-search-results-2.4.2\n",
      "Requirement already satisfied: langchainhub in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (0.1.14)\n",
      "Requirement already satisfied: requests<3,>=2 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from langchainhub) (2.31.0)\n",
      "Requirement already satisfied: types-requests<3.0.0.0,>=2.31.0.2 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from langchainhub) (2.31.0.10)\n",
      "Requirement already satisfied: charset-normalizer<4,>=2 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from requests<3,>=2->langchainhub) (3.3.2)\n",
      "Requirement already satisfied: idna<4,>=2.5 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from requests<3,>=2->langchainhub) (3.6)\n",
      "Requirement already satisfied: urllib3<3,>=1.21.1 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from requests<3,>=2->langchainhub) (2.1.0)\n",
      "Requirement already satisfied: certifi>=2017.4.17 in c:\\users\\administrator\\desktop\\codeproject\\langchainstudy\\.venv\\lib\\site-packages (from requests<3,>=2->langchainhub) (2023.11.17)\n"
     ]
    }
   ],
   "source": [
    "! pip install google-search-results\n",
    "! pip install langchainhub"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain.agents import AgentType, Tool, initialize_agent\n",
    "from langchain.llms import OpenAI\n",
    "from langchain.memory import ConversationBufferMemory\n",
    "from langchain.utilities import SerpAPIWrapper\n",
    "search = SerpAPIWrapper()\n",
    "tools = [\n",
    "    Tool(\n",
    "        name=\"当前搜索\",\n",
    "        func=search.run,\n",
    "        description=\"当您需要回答有关时事或世界现状的问题时非常有用\",\n",
    "    ),\n",
    "]\n",
    "llm = OpenAI(temperature=0)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用 LCEL"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "from langchain import hub\n",
    "from langchain.agents.format_scratchpad import format_log_to_str\n",
    "from langchain.agents.output_parsers import ReActSingleInputOutputParser\n",
    "from langchain.tools.render import render_text_description\n",
    "prompt = hub.pull(\"hwchase17/react-chat\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "PromptTemplate(input_variables=['agent_scratchpad', 'chat_history', 'input', 'tool_names', 'tools'], template='Assistant is a large language model trained by OpenAI.\\n\\nAssistant is designed to be able to assist with a wide range of tasks, from answering simple questions to providing in-depth explanations and discussions on a wide range of topics. As a language model, Assistant is able to generate human-like text based on the input it receives, allowing it to engage in natural-sounding conversations and provide responses that are coherent and relevant to the topic at hand.\\n\\nAssistant is constantly learning and improving, and its capabilities are constantly evolving. It is able to process and understand large amounts of text, and can use this knowledge to provide accurate and informative responses to a wide range of questions. Additionally, Assistant is able to generate its own text based on the input it receives, allowing it to engage in discussions and provide explanations and descriptions on a wide range of topics.\\n\\nOverall, Assistant is a powerful tool that can help with a wide range of tasks and provide valuable insights and information on a wide range of topics. Whether you need help with a specific question or just want to have a conversation about a particular topic, Assistant is here to assist.\\n\\nTOOLS:\\n------\\n\\nAssistant has access to the following tools:\\n\\n{tools}\\n\\nTo use a tool, please use the following format:\\n\\n```\\nThought: Do I need to use a tool? Yes\\nAction: the action to take, should be one of [{tool_names}]\\nAction Input: the input to the action\\nObservation: the result of the action\\n```\\n\\nWhen you have a response to say to the Human, or if you do not need to use a tool, you MUST use the format:\\n\\n```\\nThought: Do I need to use a tool? No\\nFinal Answer: [your response here]\\n```\\n\\nBegin!\\n\\nPrevious conversation history:\\n{chat_history}\\n\\nNew input: {input}\\n{agent_scratchpad}')"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "with open('promptstore/hwchase17/react-chat.txt', 'w') as file:\n",
    "    file.write(str(prompt))\n",
    "prompt"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [],
   "source": [
    "prompt = prompt.partial(\n",
    "    tools=render_text_description(tools),\n",
    "    tool_names=\", \".join([t.name for t in tools]),\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 为了确保语言模型的输出在遇到“\\nObservation”时停止，\n",
    "# 我们使用了llm.bind方法来绑定一个停止标记。\n",
    "# 这样可以防止模型生成超出预期格式的内容，\n",
    "# 保持输出的整洁和一致性。\n",
    "llm_with_stop = llm.bind(stop=[\"\\nObservation\"])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [],
   "source": [
    "agent = (\n",
    "    {\n",
    "        \"input\": lambda x: x[\"input\"],\n",
    "        \"agent_scratchpad\": lambda x: format_log_to_str(x[\"intermediate_steps\"]),\n",
    "        \"chat_history\": lambda x: x[\"chat_history\"],\n",
    "    }\n",
    "    | prompt\n",
    "    | llm_with_stop\n",
    "    | ReActSingleInputOutputParser()\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mThought: Do I need to use a tool? No\n",
      "Final Answer: Hello, nice to meet you! I am Assistant, a large language model trained by OpenAI. How can I assist you today?\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'Hello, nice to meet you! I am Assistant, a large language model trained by OpenAI. How can I assist you today?'"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from langchain.agents import AgentExecutor\n",
    "memory = ConversationBufferMemory(memory_key=\"chat_history\")\n",
    "agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True, memory=memory)\n",
    "agent_executor.invoke({\"input\": \"你好，我是兴宇\"})[\"output\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mThought: Do I need to use a tool? Yes\n",
      "Action: 当前搜索\n",
      "Action Input: 刘德华 2023年12月30号 电影 中国 上映\u001b[0m\u001b[36;1m\u001b[1;3m{'type': 'organic_result', 'title': '金手指(2023年电影)', 'source': '維基百科'}\u001b[0m\u001b[32;1m\u001b[1;3m你知道这部电影的详情吗？\n",
      "Final Answer: 是的，金手指是一部2023年上映的香港动作喜剧电影，由刘德华担任导演和主演。它讲述了一位退休的盗贼在香港和澳门展开一系列冒险的故事。\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'是的，金手指是一部2023年上映的香港动作喜剧电影，由刘德华担任导演和主演。它讲述了一位退休的盗贼在香港和澳门展开一系列冒险的故事。'"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"刘德华在2023年12月30号有什么电影将会在中国上映?\"})[\"output\"]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 使用现成的代理"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "agent_executor = initialize_agent(\n",
    "    tools,\n",
    "    llm,\n",
    "    agent=AgentType.CONVERSATIONAL_REACT_DESCRIPTION,\n",
    "    verbose=True,\n",
    "    memory=memory,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "\n",
      "\u001b[1m> Entering new AgentExecutor chain...\u001b[0m\n",
      "\u001b[32;1m\u001b[1;3mThought: Do I need to use a tool? Yes\n",
      "Action: 当前搜索\n",
      "Action Input: 刘德华 2023年12月30号 中国 上映\u001b[0m\n",
      "Observation: \u001b[36;1m\u001b[1;3m{'type': 'organic_result', 'title': '金手指(2023年电影)', 'source': '維基百科'}\u001b[0m\n",
      "Thought:\u001b[32;1m\u001b[1;3m Do I need to use a tool? No\n",
      "AI: 是的，金手指是一部2023年上映的香港动作喜剧电影，由刘德华担任导演和主演。它讲述了一位退休的盗贼在香港和澳门展开一系列冒险的故事。\u001b[0m\n",
      "\n",
      "\u001b[1m> Finished chain.\u001b[0m\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'是的，金手指是一部2023年上映的香港动作喜剧电影，由刘德华担任导演和主演。它讲述了一位退休的盗贼在香港和澳门展开一系列冒险的故事。'"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "agent_executor.invoke({\"input\": \"刘德华在2023年12月30号有什么电影将会在中国上映?\"})[\"output\"]"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
